package priv.wangy.micro.common.config.feign.handler;

import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import priv.wangy.micro.common.exception.ServiceException;
import priv.wangy.micro.common.config.feign.decoder.FullHttpRspnDecoder;
import priv.wangy.micro.common.po.http.rspn.BaseHttpResponse;
import priv.wangy.micro.common.po.http.rspn.FullHttpResponse;
import priv.wangy.micro.common.po.http.rspn.code.SysErrorEnum;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Objects;

/**
 * @author zhangjq
 * @since 2023-11-28
 */
@Slf4j
@Component
public class FeignClientHandler {

    public static final String EXCEPTION_FORMAT = "业务系统接口[%s-%s]请求失败";

    /**
     * 请求业务系统接口
     * 无请求参数
     * 发生错误、响应为空时抛出异常
     * 返回BaseHttpResponse
     *
     * @param client     业务系统接口
     * @param methodName 接口名称
     * @return com.whminwei.edu.http.rspn.BaseHttpResponse
     * @throws NoSuchMethodException     找不到接口类或接口方法
     * @throws InvocationTargetException 接口请求中发生异常
     * @throws IllegalAccessException    获取示例时出现错误
     * @throws ServiceException          接口响应异常
     * @author zhangjq
     * @since 2023-11-28
     */
    public <C> BaseHttpResponse execute(C client, String methodName) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException, ServiceException {
        Method method = client.getClass().getMethod(methodName);
        BaseHttpResponse response = (BaseHttpResponse) method.invoke(client);
        if (Objects.isNull(response)) {
            throw new ServiceException(String.format(EXCEPTION_FORMAT, client.getClass().getName(), method.getName()),
                    SysErrorEnum.EXTERNAL_API_REQ_FAILED);
        }
        return response;
    }

    /**
     * 请求业务系统接口
     * 无请求参数
     * 发生错误、响应为空时不抛出异常，返回null
     * 正常返回BaseHttpResponse
     *
     * @param client     业务系统接口
     * @param methodName 接口名称
     * @return com.whminwei.edu.http.rspn.BaseHttpResponse
     * @author zhangjq
     * @since 2023-11-28
     */
    public <C> BaseHttpResponse executeDntExc(C client, String methodName) {
        try {
            return execute(client, methodName);
        } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException | ServiceException e) {
            log.error(e.getMessage(), e);
            return null;
        }
    }

    /**
     * 请求业务系统接口
     * 有请求参数
     * 发生错误、响应为空时抛出异常
     * 返回BaseHttpResponse
     *
     * @param client     业务系统接口
     * @param methodName 接口名称
     * @param req        请求参数
     * @return com.whminwei.edu.http.rspn.BaseHttpResponse
     * @throws NoSuchMethodException     找不到接口类或接口方法
     * @throws InvocationTargetException 接口请求中发生异常
     * @throws IllegalAccessException    获取示例时出现错误
     * @throws ServiceException          接口响应异常
     * @author zhangjq
     * @since 2023-11-28
     */
    public <C, R> BaseHttpResponse execute(C client, String methodName, R req) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException, ServiceException {
        Method method = client.getClass().getMethod(methodName, req.getClass());
        BaseHttpResponse response = (BaseHttpResponse) method.invoke(client, req);
        if (Objects.isNull(response)) {
            throw new ServiceException(String.format(EXCEPTION_FORMAT, client.getClass().getName(), method.getName()),
                    SysErrorEnum.EXTERNAL_API_REQ_FAILED);
        }
        return response;
    }

    /**
     * 请求业务系统接口
     * 有请求参数
     * 发生错误、响应为空时不抛出异常，返回null
     * 正常返回BaseHttpResponse
     *
     * @param client     业务系统接口
     * @param methodName 接口名称
     * @param req        请求参数
     * @return com.whminwei.edu.http.rspn.BaseHttpResponse
     * @author zhangjq
     * @since 2023-11-28
     */
    public <C, R> BaseHttpResponse executeDntExc(C client, String methodName, R req) {
        try {
            return execute(client, methodName, req);
        } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException | ServiceException e) {
            log.error(e.getMessage(), e);
            return null;
        }
    }

    /**
     * 请求业务系统接口
     * 无请求参数
     * 发生错误、响应为空时抛出异常
     * 返回FullHttpResponse<S>
     *
     * @param client     业务系统接口
     * @param methodName 接口名称
     * @param rspnClazz  响应对象类型
     * @return com.whminwei.edu.http.rspn.FullHttpResponse
     * @throws NoSuchMethodException     找不到接口类或接口方法
     * @throws InvocationTargetException 接口请求中发生异常
     * @throws IllegalAccessException    获取示例时出现错误
     * @throws ServiceException          接口响应异常
     * @author zhangjq
     * @since 2023-11-28
     */
    @SuppressWarnings("unchecked")
    public <C, S> FullHttpResponse<S> execute(C client, String methodName, Class<S> rspnClazz) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException, ServiceException {
        Method method = client.getClass().getMethod(methodName);
        FullHttpRspnDecoder.setRspnType(rspnClazz);
        FullHttpResponse<S> response = (FullHttpResponse<S>) method.invoke(client);
        if (Objects.isNull(response)) {
            throw new ServiceException(String.format(EXCEPTION_FORMAT, client.getClass().getName(), method.getName()),
                    SysErrorEnum.EXTERNAL_API_REQ_FAILED);
        }
        return response;
    }

    /**
     * 请求业务系统接口
     * 无请求参数
     * 发生错误、响应为空时不抛出异常，返回null
     * 正常返回FullHttpResponse<S>
     *
     * @param client     业务系统接口
     * @param methodName 接口名称
     * @param rspnClazz  响应对象类型
     * @return com.whminwei.edu.http.rspn.FullHttpResponse
     * @author zhangjq
     * @since 2023-11-28
     */
    public <C, S> FullHttpResponse<S> executeDntExc(C client, String methodName, Class<S> rspnClazz) {
        try {
            return execute(client, methodName, rspnClazz);
        } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException | ServiceException e) {
            log.error(e.getMessage(), e);
            return null;
        }
    }

    /**
     * 请求业务系统接口
     * 有请求参数
     * 发生错误、响应为空时抛出异常
     * 返回FullHttpResponse<S>
     *
     * @param client     业务系统接口
     * @param methodName 接口名称
     * @param req        请求参数
     * @param rspnClazz  响应对象类型
     * @return com.whminwei.edu.http.rspn.FullHttpResponse
     * @throws NoSuchMethodException     找不到接口类或接口方法
     * @throws InvocationTargetException 接口请求中发生异常
     * @throws IllegalAccessException    获取示例时出现错误
     * @throws ServiceException          接口响应异常
     * @author zhangjq
     * @since 2023-11-28
     */
    @SuppressWarnings("unchecked")
    public <C, R, S> FullHttpResponse<S> execute(C client, String methodName, R req, Class<S> rspnClazz) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException, ServiceException {
        Method method = client.getClass().getMethod(methodName, req.getClass());
        FullHttpRspnDecoder.setRspnType(rspnClazz);
        FullHttpResponse<S> response = (FullHttpResponse<S>) method.invoke(client, req);
        if (Objects.isNull(response)) {
            throw new ServiceException(String.format(EXCEPTION_FORMAT, client.getClass().getName(), method.getName()),
                    SysErrorEnum.EXTERNAL_API_REQ_FAILED);
        }
        return response;
    }

    /**
     * 请求业务系统接口
     * 有请求参数
     * 发生错误、响应为空时不抛出异常，返回null
     * 正常返回FullHttpResponse<S>
     *
     * @param client     业务系统接口
     * @param methodName 接口名称
     * @param req        请求参数
     * @param rspnClazz  响应对象类型
     * @return com.whminwei.edu.http.rspn.FullHttpResponse
     * @author zhangjq
     * @since 2023-11-28
     */
    public <C, R, S> FullHttpResponse<S> executeDntExc(C client, String methodName, R req, Class<S> rspnClazz) {
        try {
            return execute(client, methodName, req, rspnClazz);
        } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException | ServiceException e) {
            log.error(e.getMessage(), e);
            return null;
        }
    }

    /**
     * 请求业务系统接口
     * 无请求参数
     * 发生错误、响应为空或响应结果未失败时抛出异常
     * 返回S
     *
     * @param client     业务系统接口
     * @param methodName 接口名称
     * @param rspnClazz  响应对象类型
     * @return S
     * @throws NoSuchMethodException     找不到接口类或接口方法
     * @throws InvocationTargetException 接口请求中发生异常
     * @throws IllegalAccessException    获取示例时出现错误
     * @throws ServiceException          接口响应异常
     * @author zhangjq
     * @since 2023-11-28
     */
    @SuppressWarnings("unchecked")
    public <C, S> S executeRawRspn(C client, String methodName, Class<S> rspnClazz) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException, ServiceException {
        Method method = client.getClass().getMethod(methodName);
        FullHttpRspnDecoder.setRspnType(rspnClazz);
        FullHttpResponse<S> response = (FullHttpResponse<S>) method.invoke(client);
        if (Objects.isNull(response) || !response.isResult()) {
            throw new ServiceException(String.format(EXCEPTION_FORMAT, client.getClass().getName(), method.getName()),
                    SysErrorEnum.EXTERNAL_API_REQ_FAILED);
        }
        return response.getRspnJson();
    }

    /**
     * 请求业务系统接口
     * 无请求参数
     * 发生错误、响应为空或响应结果未失败时不抛出异常，返回null
     * 正常返回S
     *
     * @param client     业务系统接口
     * @param methodName 接口名称
     * @param rspnClazz  响应对象类型
     * @return S
     * @author zhangjq
     * @since 2023-11-28
     */
    public <C, S> S executeRawRspnDntExc(C client, String methodName, Class<S> rspnClazz) {
        try {
            return executeRawRspn(client, methodName, rspnClazz);
        } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException |
                 ServiceException e) {
            log.error(e.getMessage(), e);
            return null;
        }
    }

    /**
     * 请求业务系统接口
     * 无请求参数
     * 发生错误、响应为空或响应结果未失败时不抛出异常，返回新的S实例
     *
     * @param client     业务系统接口
     * @param methodName 接口名称
     * @param rspnClazz  响应对象类型
     * @param params     响应对象的构造参数
     * @return S
     * @author zhangjq
     * @since 2023-11-28
     */
    public <C, S> S executeRawRspnNewIns(C client, String methodName, Class<S> rspnClazz, FeignClientParam... params) {
        try {
            S s = executeRawRspnDntExc(client, methodName, rspnClazz);
            return Objects.nonNull(s) ? s : rspnClazz
                    .getDeclaredConstructor(
                            Arrays.stream(params).map(FeignClientParam::getType).toArray(Class[]::new))
                    .newInstance(
                            Arrays.stream(params).map(FeignClientParam::getValue).toArray(Object[]::new));
        } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException |
                 InstantiationException e) {
            log.error(e.getMessage(), e);
            return null;
        }
    }

    /**
     * 请求业务系统接口
     * 有请求参数
     * 发生错误、响应为空或响应结果未失败时抛出异常
     * 返回S
     *
     * @param client     业务系统接口
     * @param methodName 接口名称
     * @param req        请求参数
     * @param rspnClazz  响应对象类型
     * @return com.whminwei.edu.http.rspn.BaseHttpResponse
     * @throws NoSuchMethodException     找不到接口类或接口方法
     * @throws InvocationTargetException 接口请求中发生异常
     * @throws IllegalAccessException    获取示例时出现错误
     * @throws ServiceException          接口响应异常
     * @author zhangjq
     * @since 2023-11-28
     */
    @SuppressWarnings("unchecked")
    public <C, R, S> S executeRawRspn(C client, String methodName, R req, Class<S> rspnClazz) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException, ServiceException {
        Method method = client.getClass().getMethod(methodName, req.getClass());
        FullHttpRspnDecoder.setRspnType(rspnClazz);
        FullHttpResponse<S> response = (FullHttpResponse<S>) method.invoke(client, req);
        if (Objects.isNull(response)) {
            throw new ServiceException(String.format(EXCEPTION_FORMAT, client.getClass().getName(), method.getName()),
                    SysErrorEnum.EXTERNAL_API_REQ_FAILED);
        }
        return response.getRspnJson();
    }

    /**
     * 请求业务系统接口
     * 有请求参数
     * 发生错误、响应为空或响应结果未失败时不抛出异常，返回null
     * 正常返回S
     *
     * @param client     业务系统接口
     * @param methodName 接口名称
     * @param req        请求参数
     * @param rspnClazz  响应对象类型
     * @return com.whminwei.edu.http.rspn.BaseHttpResponse
     * @author zhangjq
     * @since 2023-11-28
     */
    public <C, R, S> S executeRawRspnDntExc(C client, String methodName, R req, Class<S> rspnClazz) {
        try {
            return executeRawRspn(client, methodName, req, rspnClazz);
        } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException |
                 ServiceException e) {
            log.error(e.getMessage(), e);
            return null;
        }
    }

    /**
     * 请求业务系统接口
     * 有请求参数
     * 发生错误、响应为空或响应结果未失败时不抛出异常，返回新的S实例
     *
     * @param client     业务系统接口
     * @param methodName 接口名称
     * @param req        请求参数
     * @param rspnClazz  响应对象类型
     * @param params     响应对象的构造参数
     * @return com.whminwei.edu.http.rspn.BaseHttpResponse
     * @author zhangjq
     * @since 2023-11-28
     */
    public <C, R, S> S executeRawRspnNewIns(C client, String methodName, R req, Class<S> rspnClazz, FeignClientParam... params) {
        try {
            S s = executeRawRspnDntExc(client, methodName, req, rspnClazz);
            return Objects.nonNull(s) ? s : rspnClazz
                    .getDeclaredConstructor(
                            Arrays.stream(params).map(FeignClientParam::getType).toArray(Class[]::new))
                    .newInstance(
                            Arrays.stream(params).map(FeignClientParam::getValue).toArray(Object[]::new));
        } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException |
                 InstantiationException e ) {
            log.error(e.getMessage(), e);
            return null;
        }
    }
}
